#include <windows.h>
#include "CDXSwapChain.h"
#include "CReleaseMacro.h"
#include <assert.h>
CDXSwapChain::CDXSwapChain(CDXDevice* pDevice) : CDXTexture2D(pDevice)
{
	m_pSwapChain = NULL;
}
CDXSwapChain::~CDXSwapChain()
{
	SAFE_RELEASE(m_pSwapChain);
	ReleaseResources();
}

HRESULT CDXSwapChain::ReleaseResources()
{
	return __super::ReleaseResources();
}
HRESULT CDXSwapChain::_CreateCompitableTexture()
{
	if (m_pSwapChain == NULL)
	{
		assert(0);
		return E_FAIL;
	}
	HRESULT hr = S_OK;
	DXGI_SWAP_CHAIN_DESC sd;
	m_pSwapChain->GetDesc(&sd);
	HWND desktopHwnd = GetDesktopWindow();
	RECT desktopRect;
	GetWindowRect(desktopHwnd, &desktopRect);
	UINT texW = desktopRect.right - desktopRect.left;
	UINT texH = desktopRect.bottom - desktopRect.top;
	texW = min(4096, texW);
	texH = min(4096, texH);

	D3D11_TEXTURE2D_DESC desc;
	desc.Width = texW;
	desc.Height = texH;
	desc.ArraySize = 1 ;
	desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
	desc.Format = sd.BufferDesc.Format;
	desc.CPUAccessFlags = 0;
	desc.MipLevels = 1;
	desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
	desc.Usage = D3D11_USAGE_DEFAULT;
	desc.SampleDesc.Count = 1;
	desc.SampleDesc.Quality = 0; 

	hr = CDXTexture2D::Create(&desc, NULL);
	return hr;
}

HRESULT CDXSwapChain::CreateEx(DXGI_SWAP_CHAIN_DESC * pDesc)
{
	if (m_pDevice == NULL)
		return E_FAIL;
	SAFE_RELEASE(m_pSwapChain);
	HRESULT hr = S_OK;
	IDXGIFactory1* pDXGIFactory = NULL;  
	hr = m_pDevice->GetDXGIFactory(&pDXGIFactory);
	if (FAILED(hr))
		return hr;
	ID3D11Device* pDX11Device = m_pDevice->GetD3D11Device();
	hr = pDXGIFactory->CreateSwapChain(pDX11Device, pDesc, &m_pSwapChain );
	if (FAILED(hr))
		return hr;
	hr = _CreateCompitableTexture();
	return hr;
}

HRESULT CDXSwapChain::Create(HWND hwnd)
{
	if (m_pDevice == NULL || hwnd == NULL)
		return E_FAIL;
	SAFE_RELEASE(m_pSwapChain);
	HRESULT hr = S_OK;
	IDXGIFactory1* pDXGIFactory = NULL;  
	hr = m_pDevice->GetDXGIFactory(&pDXGIFactory);
	if (FAILED(hr))
		return hr;

	DXGI_SWAP_CHAIN_DESC sd;
	ZeroMemory( &sd, sizeof( sd ) );
	sd.BufferCount = 1;
	sd.BufferDesc.Width = 0;
	sd.BufferDesc.Height = 0;
	sd.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
	sd.BufferDesc.RefreshRate.Numerator = 60;
	sd.BufferDesc.RefreshRate.Denominator = 1;
	sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	sd.OutputWindow = hwnd;
	sd.SampleDesc.Count = 1;
	sd.SampleDesc.Quality = 0;
	sd.Windowed = TRUE;
	ID3D11Device* pDX11Device = m_pDevice->GetD3D11Device();
	hr = pDXGIFactory->CreateSwapChain(pDX11Device, &sd, &m_pSwapChain);
	if (FAILED(hr))
		return hr;
	hr = _CreateCompitableTexture();

	return hr;
}


IDXGISwapChain* CDXSwapChain::GetDXGISwapChain()
{
	return m_pSwapChain;
}
HRESULT CDXSwapChain::ResizeBuffer(UINT width, UINT height)
{
	if (m_pSwapChain == NULL)
		return E_FAIL;
	HRESULT hr = S_OK;
	DXGI_SWAP_CHAIN_DESC desc;
	m_pSwapChain->GetDesc(&desc);
	hr = ResizeBuffer(desc.BufferCount, width, height, desc.BufferDesc.Format, 
		desc.Flags);
	if (FAILED(hr))
		return hr;
	return hr;
}
HRESULT CDXSwapChain::ResizeBuffer(UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags)
{
	if (m_pSwapChain == NULL)
		return E_FAIL;
	HRESULT hr = S_OK;
	hr = m_pSwapChain->ResizeBuffers(BufferCount, Width, Height, NewFormat, SwapChainFlags);
	if (FAILED(hr))
		return hr;
	return hr;
}
HRESULT CDXSwapChain::GetFrameSize(UINT* width, UINT* height)
{
	if (width == NULL || height == NULL)
	{
		assert(0);
		return E_FAIL;
	}
	if (m_pSwapChain == NULL )
	{
		assert(0);
		return E_FAIL;
	}
	DXGI_SWAP_CHAIN_DESC desc;
	m_pSwapChain->GetDesc(&desc);
	*width = desc.BufferDesc.Width;
	*height = desc.BufferDesc.Height;
	return S_OK;
}

HRESULT CDXSwapChain::SetFullscreen(BOOL bFullscreen)
{
	if (m_pSwapChain == NULL)
		return E_FAIL;
	return m_pSwapChain->SetFullscreenState(bFullscreen, NULL);
}

HRESULT CDXSwapChain::GetFullscreen(BOOL& bFullscreen)
{
	if (m_pSwapChain == NULL)
		return E_FAIL;
	HRESULT hr = S_OK;
	IDXGIOutput* pOutput = NULL;
	hr = m_pSwapChain->GetFullscreenState(&bFullscreen, &pOutput);
	SAFE_RELEASE(pOutput);
	return hr;
}
HRESULT CDXSwapChain::Present()
{
	if (m_pSwapChain == NULL || m_pTexture == NULL)
		return E_FAIL;
	_CopyContentToSwapChain();
	return m_pSwapChain->Present(0, 0);
}
HRESULT CDXSwapChain::_CopyContentToSwapChain()
{
	if (m_pSwapChain == NULL || m_pTexture == NULL || m_pDevice == NULL)
	{
		assert(0);
		return E_FAIL;
	}
	HRESULT hr = S_OK;
	ID3D11DeviceContext* pContext = m_pDevice->GetD3D11DeviceContext();
	
	ID3D11Texture2D* pSwapChainTexture = NULL;
	hr = m_pSwapChain->GetBuffer(0, __uuidof(pSwapChainTexture), reinterpret_cast<void**>(&pSwapChainTexture));
	if (FAILED(hr))
	{
		assert(0);
		return E_FAIL;
	}
	UINT frameW =0, frameH = 0;
	hr = GetFrameSize(&frameW, &frameH);
	if (FAILED(hr))
	{
		assert(0);
		return E_FAIL;
	}
	D3D11_BOX srcRegion;
	srcRegion.left = 0; srcRegion.right = frameW-1;
	srcRegion.top = 0, srcRegion.bottom = frameH-1;
	srcRegion.front = 0;
	srcRegion.back = 1;
	hr = KeyMutex11Acquire();
	pContext->CopySubresourceRegion(pSwapChainTexture, 0, 0, 0, 0, m_pTexture, 0, &srcRegion );
	hr = KeyMutex11Release();
	SAFE_RELEASE(pSwapChainTexture);
	return S_OK;
}